#pragma once

#include <libmodbus/modbus.h>

#include <condition_variable>
#include <functional>
#include <map>
#include <memory>
#include <mutex>
#include <queue>
#include <string>
#include <thread>
#include <vector>

// Forward declaration
struct PortContext;

enum MB_DataOrder { MB_ABCD, MB_BADC, MB_CDAB, MB_DCBA };

class Modbus
{
public:
    Modbus();
    ~Modbus();
    bool set_config_tcp(std::string ip_addr, uint32_t port, uint8_t unit_id, uint32_t timeout_s = 2,
                        uint32_t timeout_ms = 0);
    bool set_config_rtu(std::string port, uint32_t baud, uint8_t slave_addr, uint32_t timeout_s = 0,
                        uint32_t timeout_ms = 500);
    bool read_data(uint16_t address, uint16_t length, std::vector<uint16_t>& data);
    bool read_data(uint16_t address, uint16_t length, std::vector<float>& data, MB_DataOrder order = MB_ABCD);
    bool write_data(uint16_t address, uint16_t length, const std::vector<uint16_t>& data);
    bool write_data(uint16_t address, uint16_t length, const std::vector<float>& data, MB_DataOrder order = MB_ABCD);
    void async_read_data(uint16_t address, uint16_t length, std::function<void(bool, std::vector<uint16_t>&)> callback);
    void async_read_data(uint16_t address, uint16_t length, std::function<void(bool, std::vector<float>&)> callback,
                         MB_DataOrder order = MB_ABCD);
    void async_write_data(uint16_t address, uint16_t length, const std::vector<uint16_t>& data,
                          std::function<void(bool)> callback);
    void async_write_data(uint16_t address, uint16_t length, const std::vector<float>& data,
                          std::function<void(bool)> callback, MB_DataOrder order = MB_ABCD);
    std::string get_error_msg()
    {
        return error_msg;
    };

private:
    std::string error_msg;
    std::shared_ptr<PortContext> m_port_ctx;  // Added: Holds the shared port context
    uint8_t m_slave_id;                       // Added: Slave ID for this Modbus instance

    std::thread m_async_thread;                 // 专用异步线程
    std::queue<std::function<void()>> m_tasks;  // 任务队列
    std::mutex m_task_mutex;                    // 保护任务队列
    std::condition_variable m_task_cv;          // 用于任务通知
    bool m_running{true};                       // 线程运行标志

    void async_thread_func();  // 线程函数

    // Added: Manages shared PortContext objects
    static std::map<std::string, std::shared_ptr<PortContext>> s_port_contexts;
    static std::mutex s_contexts_map_mutex;  // Mutex for s_port_contexts map
};

// Added: Structure to hold shared Modbus context and its specific mutex
struct PortContext {
    modbus_t* ctx{nullptr};
    std::mutex operation_mutex;  // Mutex for operations on this specific ctx
    std::string identifier;      // e.g., "rtu:/dev/ttyS0" or "tcp:192.168.1.1:502"
    // int reference_count{0}; // std::shared_ptr handles reference counting

    PortContext(const std::string& id, modbus_t* mb_ctx) : identifier(id), ctx(mb_ctx)
    {
    }

    ~PortContext()
    {
        if (ctx) {
            modbus_close(ctx);
            modbus_free(ctx);
            ctx = nullptr;
        }
    }

    // Prevent copying and assignment
    PortContext(const PortContext&) = delete;
    PortContext& operator=(const PortContext&) = delete;
    PortContext(PortContext&&) = delete;
    PortContext& operator=(PortContext&&) = delete;
};